Use a multi-stage Docker build: compile in a golang image, then copy only the binary to a distroless or scratch image. Result is a 5-15MB image vs 800MB+ with the full Go image.
distroless/static: ~3MB base, includes CA certs and timezone data — recommended for most services
scratch: 0 bytes base — only works if your binary is 100% static and you don't need CA certs
-ldflags '-w -s' strips debug info — reduces binary size by 20-30%
Cache go mod download layer separately — rebuilds only when go.mod/go.sum change
Run as non-root user in production — distroless nonroot image provides uid 65532